package structure

import (
	"product/common/pointer"
	"reflect"
)

// Field 结构字段信息
type Field struct {
	Structure                     // 结构描述
	field     reflect.StructField // 结构字段信息
	tag       *Tag                // 结构字段标签信息
}

// NewField 创建字段信息
//
//	v: 结构体值
//	f: 结构体字段
//	tagName: 标签名称
func newField(v reflect.Value, f reflect.StructField, tagName string) *Field {
	tag := f.Tag.Get(tagName)
	field := &Field{
		field: f,
		tag:   newTag(tag),
	}
	field.rValue = v
	field.rType = v.Type()
	field.TagName = tagName
	return field
}

// Tag 获取标签信息
// 返回标签信息
func (t *Field) Tag() *Tag {
	return t.tag
}

// Value 获取字段值
// 返回字段值
func (t *Field) Value() any {
	return t.rValue.Interface()
}

// IsEmbedded 是否嵌套
func (t *Field) IsEmbedded() bool {
	return len(t.field.Index) > 1
}

// IsExported 是否导出
func (t *Field) IsExported() bool {
	return t.field.IsExported()
}

// IsZero 是否为零值
// 返回是否为零值
func (t *Field) IsZero() bool {
	z := reflect.Zero(t.rValue.Type()).Interface()
	v := t.Value()
	return reflect.DeepEqual(z, v)
}

// IsNil 是否为空
func (t *Field) IsNil() bool {
	v := t.Value()
	if v == nil || (reflect.ValueOf(v)).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil() {
		return true
	}
	return false
}

// Name 获取字段名称
func (t *Field) Name() string {
	return t.field.Name
}

// FieldType 获取字段类型
func (t *Field) FieldType() reflect.Kind {
	return t.rValue.Kind()
}

// IsSlice 是否为切片
func (t *Field) IsSlice() bool {
	k := t.rValue.Kind()
	return k == reflect.Slice
}

// IsTargetType 是否为指定类型
func (t *Field) IsTargetType(targetType reflect.Kind) bool {
	return t.rValue.Kind() == targetType
}

// mapValue 映射值
// value: 值
// 返回映射值
func (t *Field) mapValue(value any) any {
	val := pointer.ExtractPointer(value)
	v := reflect.ValueOf(val)
	var ret any

	switch v.Kind() {
	case reflect.Struct:
		s := NewStructure(val)
		s.TagName = t.TagName
		m, _ := s.ToMap()
		ret = m
	case reflect.Map:
		mapEl := v.Type().Elem()
		switch mapEl.Kind() {
		case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan:
			// iterate the map
			m := make(map[string]any, v.Len())
			for _, key := range v.MapKeys() {
				m[key.String()] = t.mapValue(v.MapIndex(key).Interface())
			}
			ret = m
		default:
			ret = v.Interface()
		}
	case reflect.Slice, reflect.Array:
		sEl := v.Type().Elem()
		switch sEl.Kind() {
		case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan:
			slices := make([]any, v.Len())
			for i := 0; i < v.Len(); i++ {
				slices[i] = t.mapValue(v.Index(i).Interface())
			}
			ret = slices
		default:
			ret = v.Interface()
		}
	default:
		if v.Kind().String() != "invalid" {
			ret = v.Interface()
		}
	}
	return ret
}
